/*
Copyright 2010 Thomas W. Holtquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using System;
using System.Ext.Xml;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;

using Microsoft.SPOT;

using Skewworks.Pyxis.GUI.Controls;

namespace Skewworks.Pyxis.Kernel
{

    internal class WebApp
    {

        #region Variables

        private PyxisAPI API;
        private form AppForm;
        private string curPage = string.Empty;
        private string curURL = string.Empty;

        #endregion

        #region Constructor

        public WebApp(PyxisAPI api)
        {
            API = api;
            AppForm = new form(api, Colors.LightGray, true, true);
        }

        #endregion

        #region Public Methods

        public void Activate()
        {
            LoadApp("http://www.skewworks.com/uWA/home.pwam");
        }

        #endregion

        #region Private Methods

        private void LoadApp(string url)
        {
            point pt = new point(4, 4);

            // Prepare
            curPage = string.Empty;
            AppForm.Controls.Clear();
            if (API.desktop._mnu.count > 1)
            {
                API.desktop._mnu.GetItemAt(1).text = "Loading...";
            }
            else
            {
                API.desktop._mnu.add(new menuitem("Loading..."));
            }

            // API only called the render if it's a changed form
            if (API.ActiveForm == AppForm)
            {
                AppForm.Render();
            }
            else API.ActiveForm = AppForm;

            // Read Data
            byte[] data = API.MyNetwork.DownloadURL(url);
            if (data == null)
            {
                API.desktop._mnu.GetItemAt(1).text = "Done [No App]";
                return;
            }

            // Display Page
            try
            {
                XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();

                xmlReaderSettings.IgnoreComments = true;
                xmlReaderSettings.IgnoreProcessingInstructions = true;
                xmlReaderSettings.IgnoreWhitespace = true;

                MemoryStream stream = new MemoryStream(data);
                XmlReader reader = XmlReader.Create(stream, xmlReaderSettings);
                string temp;

                // Read Top Level Info
                if (!reader.ReadToDescendant("PWAM")) throw new ArgumentException("PWAM not detected");
                if (!reader.ReadToDescendant("HEAD")) throw new ArgumentException("HEAD not detected");
                if (reader.ReadToFollowing("TITLE"))
                {
                    reader.Read();
                    curPage = reader.Value;
                    API.desktop._mnu.GetItemAt(1).text = curPage + " [Loading]";
                }
                else throw new ArgumentException("TITLE not detected");

                if (reader.ReadToFollowing("CONTENT"))
                {
                    if (reader.HasAttributes)
                    {
                        temp = reader.GetAttribute("background");
                        if (temp != string.Empty) AppForm.backcolor = Colors.FromString(temp);
                    }
                }
                else throw new ArgumentException("CONTENT not detected");

                // Create Elements
                try
                {
                    while (reader.Read() && !(reader.NodeType == XmlNodeType.EndElement && reader.Name == "CONTENT"))
                    {
                        try
                        {
                            switch (reader.Name)
                            {
                                case "img":
                                    pt = AddIMG(reader, pt);
                                    break;
                                case "p":
                                    pt = AddParagraph(reader, pt);
                                    break;
                                case "a":
                                    AddLink(reader, pt);
                                    break;
                                case "br":
                                    pt.x = 4;
                                    pt.y += 16;
                                    break;
                            }
                        }
                        catch (Exception)
                        {
                            // Move along
                        }
                    }
                }
                catch (Exception)
                {
                    // Move along
                }
                reader.Close();


                API.desktop._mnu.GetItemAt(1).text = curPage;
            }
            catch (Exception e)
            {
                API.desktop._mnu.GetItemAt(1).text = "Done [Error Occurred]";
                Debug.Print("Error: " + e.Message);
            }

        }

        private point AddIMG(XmlReader reader, point pt)
        {
            string src = reader.GetAttribute("src");
            string width = reader.GetAttribute("width");
            string height = reader.GetAttribute("height");

            if (width == string.Empty) width = "20";
            if (height == string.Empty) height = "20";

            int w = int.Parse(width);
            int h = int.Parse(height);
            int x = pt.x;
            int y = pt.y;

            if (x + w > AppearanceManager.ScreenWidth)
            {
                x = 4;
                y += 20;
            }

            byte[] imgData = API.MyNetwork.DownloadURL(src);


            picturebox pbox = new picturebox(PyxisAPI.ImageFromBytes(imgData), x, y, w, h, BorderStyle.BorderNone, ScaleMode.Normal);
            AppForm.AddChild(pbox);
            AppForm.Render();

            return new point(4, y + h);
        }

        private point AddLink(XmlReader reader, point pt)
        {
            string href = reader.GetAttribute("href");
            reader.Read();
            string text = reader.Value;
            reader.Read();

            text = API.StringReplace(text, "\n", " ");
            text = API.StringReplace(text, "  ", " ");

            int x = pt.x;
            int y = pt.y;
            int w, h;
            Font fnt = FontManager.Tahoma11;
            fnt.ComputeExtent(text, out w, out h);
            if (w + x > AppForm.width - 4)
            {
                // Too big; new line
                x = 4;
                y = y + fnt.Height + 4;
                fnt.ComputeTextInRect(text, out w, out h, AppForm.width - 8);
            }

            label lnk = new label(text, x, y, w, h);
            lnk.color = Colors.Blue;
            lnk.tapEvent += new OnTap((object sender, point e) => LoadApp(href));
            AppForm.AddChild(lnk);
            AppForm.Render();

            return new point(x + w + 4, y);
        }

        private point AddParagraph(XmlReader reader, point pt)
        {
            reader.Read();
            string sVal = reader.Value;
            reader.Read();

            sVal = API.StringReplace(sVal, "\n", " ");
            sVal = API.StringReplace(sVal, "  ", " ");

            // Paragraphs always get a new line
            int x = 4;
            int y = pt.y + 4;
            int w, h;
            Font fnt = FontManager.Tahoma11;
            fnt.ComputeTextInRect(sVal, out w, out h, AppForm.width - 8);

            AppForm.AddChild(new label(sVal, x, y, w, h));
            AppForm.Render();

            return new point(4, y + h + 4);
        }

        #endregion

    }

}
